#include "StdAfx.h"
#include "WEILayer.h"
#include "WceUiRealWnd.h"
#include "WEGlobal.h"
#include "WEIButton.h"

#define SEND_CMD_DOWN_TIMER  65533
#define SLIDERING_TIMER 65534


CWEILayer::CWEILayer(void)
{
	m_type = E_ILAYER_TYPE_V;
	m_rcVisual.SetRect(0, 0, WceUiGetScreenWidth(), WceUiGetScreenHeight());
	m_status = E_ILAYER_UNINIT;
	m_bCmdDownSended = FALSE;
	m_dwBeforeSliderTick = 0;

	m_nFast		= 3;
	m_nNormal	= 2;
	m_nSlow		= 1;

	m_nPage		= m_nNormal;

	m_nFreq		= 30;
	m_dwLastSlideTick = 0;
	m_bBlockSlide = FALSE;
}

CWEILayer::~CWEILayer(void)
{

}

void CWEILayer::SetProperties(PCWceUiXmlElem pCreateElem)
{
	CWceUiLayer::SetProperties(pCreateElem);

	E_ILAYER_TYPE type = E_ILAYER_TYPE_V;
	CRect rcVisual(0, 0, WceUiGetScreenWidth(), WceUiGetScreenHeight());

	LPCTSTR pType = pCreateElem->GetAttr(L"way");
	if ((NULL != pType) && (0 == _tcsicmp(pType, L"h")))
	{
		type = E_ILAYER_TYPE_H;
	}

	LPCTSTR pVisualRect = pCreateElem->GetAttr(L"visual-rect");
	if (NULL != pVisualRect)
	{
		BOOL bTemp = ConvertRectStrToRect(pVisualRect, rcVisual);
		ASSERT(bTemp);
	}

	m_type = type;
	m_rcVisual = rcVisual;
}

void CWEILayer::OnInitLayer()
{
	E_ILAYER_TYPE type = m_type;
	CRect rcVisual = m_rcVisual;
	SetVisualRectAndType(&rcVisual, type);
}


void CWEILayer::SetVisualRectAndType(LPCRECT lpRect, E_ILAYER_TYPE type)
{
	ASSERT(NULL != lpRect);
	::CopyRect(&m_rcVisual, lpRect);
	m_type = type;
}

E_ILAYER_TYPE CWEILayer::GetVisualRectAndType(LPRECT lpRect) const
{
	ASSERT(NULL != lpRect);
	::CopyRect(lpRect, &m_rcVisual);
	return m_type;
}


void CWEILayer::OnLButtonDown(UINT nFlags, POINT point)
{
	m_bSetBeforeSliderTick = FALSE;
	switch(m_status)
	{
	case E_ILAYER_UNINIT:
		{
			KillTimer(SEND_CMD_DOWN_TIMER);
			SetTimer(SEND_CMD_DOWN_TIMER, 100);
			m_status = E_ILAYER_DOWN;
			m_downPoint = point;
			m_lastPoint = point;
			m_bCmdDownSended = FALSE;
			SetCapture();

			m_pDownLayer = NULL;
			POINT pt = point;
			WindowToClient(&pt);
			PCWceUiLayer pInd = FirstChild();
			while (pInd)
			{
				CRect rc;
				pInd->GetWindowRect(&rc);
				WindowToClient(&rc);

				if (rc.PtInRect(pt))
				{
					m_pDownLayer = pInd;
					TRACE(L"%s is down\n", m_pDownLayer->GetName());
					return;
				}
				pInd = NextChild(pInd);
			}

			if (NULL == m_pDownLayer)
			{
				m_pDownLayer = this;
			}
		}
		break;
	case E_ILAYER_SLIDE:
		{
			StopSliding();
			SetCapture();
			m_downPoint = point;
			m_lastPoint = point;
			
			m_status = E_ILAYER_MOVE;
			m_bSetBeforeSliderTick = TRUE;
		}
		break;
	case E_ILAYER_DOWN: //through
	case E_ILAYER_MOVE: //through
	default:
		break;
	}

}


void CWEILayer::OnMouseMove(UINT nFlags, POINT point)
{
	switch(m_status)
	{
	case E_ILAYER_MOVE:
		{
			if (m_bSetBeforeSliderTick)
			{
				m_dwBeforeSliderTick = GetTickCount();
				m_bSetBeforeSliderTick = FALSE;
			}

			OnMove(point);
		}
		break;
	case E_ILAYER_UNINIT: 
		break;
	case E_ILAYER_DOWN:
		{
			CPoint curPoint = point;
			int deltaX = curPoint.x - m_downPoint.x;
			int deltaY = curPoint.y - m_downPoint.y;

			if (E_ILAYER_TYPE_H == m_type)
			{
				if (abs(deltaX) < 10)
				{
					goto EndOfOnMouseMove;
				}
			}else
			{
				if (abs(deltaY) < 10)
				{
					goto EndOfOnMouseMove;
				}
			}
			SendEndDownCmd();
			m_status = E_ILAYER_MOVE;
			m_lastPoint = point;
			m_dwBeforeSliderTick = GetTickCount();
		}
		break;
	case E_ILAYER_SLIDE:  //through
	default:
		break;
	}

EndOfOnMouseMove:
	return;
}


void CWEILayer::OnLButtonUp(UINT nFlags, POINT point)
{
	ReleaseCapture();
	if (E_ILAYER_DOWN == m_status)
	{
		SendEndDownCmd();
		ASSERT(NULL != m_pDownLayer);
		OnIClick(m_pDownLayer);
		m_status = E_ILAYER_UNINIT;

	}else if (E_ILAYER_MOVE == m_status)
	{
		int nTickDiff = GetTickCount() - m_dwBeforeSliderTick;

		if ((nTickDiff < 500)
			&&CanSlide())
		{
			if (nTickDiff < 80)
			{
				m_nPage = m_nFast;
			}else if (nTickDiff < 250)
			{
				m_nPage = m_nNormal;
			}else
			{
				m_nPage = m_nSlow;
			}

			if (E_ILAYER_TYPE_H == m_type)
			{
				int deltaX = point.x - m_downPoint.x;
				m_direction = (deltaX > 0) ? E_D_ILAYER_RIGHT : E_D_ILAYER_LEFT;
				
				GetWindowRect(&m_rcBeforeSlide);
				CRect rcPosition = m_rcBeforeSlide;

				int nMinX = m_rcVisual.right - rcPosition.Width();
				int nMaxX = m_rcVisual.left;

				int nDist = m_nPage * (m_rcVisual.Width());
				if (E_D_ILAYER_RIGHT == m_direction)
				{
					m_nSlideDstLeft = rcPosition.left + nDist;
					m_nSlideDstLeft = min(m_nSlideDstLeft, nMaxX);
					m_nTotalDist = m_nSlideDstLeft - rcPosition.left;
				}else
				{
					m_nSlideDstLeft = rcPosition.left - nDist;
					m_nSlideDstLeft = max(m_nSlideDstLeft, nMinX);
					m_nTotalDist = rcPosition.left - m_nSlideDstLeft;
				}
			}else
			{
				int deltaY = point.y - m_downPoint.y;
				m_direction = (deltaY > 0) ? E_D_ILAYER_DOWN : E_D_ILAYER_UP;

				GetWindowRect(&m_rcBeforeSlide);
				CRect rcPosition = m_rcBeforeSlide;

				int nMinY = m_rcVisual.bottom - rcPosition.Height();
				int nMaxY = m_rcVisual.top;

				int nDist = m_nPage * (m_rcVisual.Height());
				if (E_D_ILAYER_DOWN == m_direction)
				{
					m_nSlideDstTop = rcPosition.top + nDist;
					m_nSlideDstTop = min(m_nSlideDstTop, nMaxY);
					m_nTotalDist = m_nSlideDstTop - rcPosition.top;
				}else
				{
					m_nSlideDstTop = rcPosition.top - nDist;
					m_nSlideDstTop = max(m_nSlideDstTop, nMinY);
					m_nTotalDist = rcPosition.top - m_nSlideDstTop;
				}

			}
			m_status = E_ILAYER_SLIDE;

			SetTimer(SLIDERING_TIMER, 5);
			
			m_nCurFame = 0;
			m_nTotalFrame = m_nTotalDist / 20 + 2;
			m_dwLastSlideTick = 0;

			if (m_bBlockSlide)
			{
				DWORD dwTick = GetTickCount();
				while (DoSliding())
				{
					GetWindow()->UpdateWindow();
					int nSleep = m_nFreq - (GetTickCount() - dwTick);
					if (nSleep > 0)
					{
						Sleep(nSleep);
					}
					m_dwLastSlideTick = 0;
					dwTick = GetTickCount();
				}
				GetWindow()->IgnoreMsgBeforeTime();
			}else
			{
				DoSliding();
			}
			
		}else
		{
			OnEndMove();
			m_status = E_ILAYER_UNINIT;
		}
	}
}


void CWEILayer::OnLoseCapture()
{
	if (E_ILAYER_DOWN == m_status)
	{
		SendEndDownCmd();
		m_status = E_ILAYER_UNINIT;
	}else if (E_ILAYER_MOVE == m_status)
	{
		m_status = E_ILAYER_UNINIT;
	}
}



void CWEILayer::OnMove(CPoint pt)
{
	CPoint curPoint = pt;

	int deltaX = curPoint.x - m_lastPoint.x;
	int deltaY = curPoint.y - m_lastPoint.y;

	CRect rcPosition;
	GetWindowRect(&rcPosition);

	int x = rcPosition.left;
	int y = rcPosition.top;

	if (E_ILAYER_TYPE_H == m_type)
	{
		int nMinX = 0;
		int nMaxX = 0;
		GetHLimit(nMinX, nMaxX);

		x = rcPosition.left + deltaX;
		x = max(x, nMinX);
		x = min(x, nMaxX);
	}else
	{
		int nMinY = 0;
		int nMaxY = 0;
		GetVLimit(nMinY, nMaxY);

		y = rcPosition.top + deltaY;
		y = max(y, nMinY);
		y = min(y, nMaxY);
	}

	SetLayerPos(x, y, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
	OnLayerMoved();
	m_lastPoint = curPoint;
}

void CWEILayer::SendEndDownCmd()
{
	if (E_ILAYER_DOWN == m_status)
	{
		if (m_bCmdDownSended)
		{
			OnCmdEndDown();
		}else
		{
			KillTimer(SEND_CMD_DOWN_TIMER);
		}
	}
}

void CWEILayer::OnTimer(WORD wIDEvent)
{
	if (SEND_CMD_DOWN_TIMER == wIDEvent)
	{
		KillTimer(SEND_CMD_DOWN_TIMER);
		if (E_ILAYER_DOWN == m_status)
		{
			m_bCmdDownSended = TRUE;
			OnCmdDown();
		}
	}else if (SLIDERING_TIMER == wIDEvent)
	{
		if (E_ILAYER_SLIDE == m_status)
		{
			DoSliding();
		}
	}
}

void CWEILayer::OnCmdDown()
{
	OnStyleDown(m_pDownLayer);
}

void CWEILayer::OnCmdEndDown()
{
	OnStyleEndDown(m_pDownLayer);
}

void CWEILayer::OnIClick(CWceUiLayer* pLayer)
{
	ASSERT(NULL != m_pDownLayer);
	GetCmdReceiver()->OnCommand(CMD_WE_I_CLICK, (WPARAM)m_pDownLayer, 0);
}

BOOL CWEILayer::DoSliding()
{
	BOOL bResult = FALSE; 
	if (E_ILAYER_SLIDE == m_status)
	{
		if ((m_nCurFame == m_nTotalFrame) || (m_nTotalDist <= 0))
		{
			StopSliding();
			m_status = E_ILAYER_UNINIT;
			return bResult;
		}

		bResult = TRUE;
		int nElapsed = GetTickCount() - m_dwLastSlideTick;
		TRACE(L"nElapsed = %d\n", nElapsed);
		if (nElapsed < m_nFreq)
		{
			return bResult;
		}

		m_dwLastSlideTick = GetTickCount();
		switch(m_direction)
		{
		case E_D_ILAYER_LEFT:
			{
				CRect rcPos = m_rcBeforeSlide;
				int nShift = wceui::CalcAnidisplacement(m_nCurFame, m_nTotalFrame, m_nTotalDist);
				rcPos.left -= nShift;
				rcPos.right -= nShift;
				MoveLayer(&rcPos);
				OnLayerMoved();
			}
			break;
		case E_D_ILAYER_RIGHT:
			{
				CRect rcPos = m_rcBeforeSlide;
				int nShift = wceui::CalcAnidisplacement(m_nCurFame, m_nTotalFrame, m_nTotalDist);
				rcPos.left += nShift;
				rcPos.right += nShift;
				MoveLayer(&rcPos);
				OnLayerMoved();
			}
			break;
		case E_D_ILAYER_UP:
			{
				CRect rcPos = m_rcBeforeSlide;
				int nShift = wceui::CalcAnidisplacement(m_nCurFame, m_nTotalFrame, m_nTotalDist);
				rcPos.top -= nShift;
				rcPos.bottom -= nShift;
				MoveLayer(&rcPos);
				OnLayerMoved();
			}
			break;
		case E_D_ILAYER_DOWN:
			{
				CRect rcPos = m_rcBeforeSlide;
				int nShift = wceui::CalcAnidisplacement(m_nCurFame, m_nTotalFrame, m_nTotalDist);
				rcPos.top += nShift;
				rcPos.bottom += nShift;
				MoveLayer(&rcPos);
				OnLayerMoved();
			}
			break;
		}
		m_nCurFame++;
	}
	return bResult;
}

void CWEILayer::StopSliding()
{
	KillTimer(SLIDERING_TIMER);
}


void CWEILayer::GetHLimit(int& nMinX, int& nMaxX)
{
	CRect rcPosition;
	GetWindowRect(&rcPosition);

	nMinX = m_rcVisual.right - (m_rcVisual.Width() >> 2) - rcPosition.Width();
	nMaxX = m_rcVisual.left + (m_rcVisual.Width() >> 2);

}

void CWEILayer::GetVLimit(int& nMinY, int& nMaxY)
{
	CRect rcPosition;
	GetWindowRect(&rcPosition);

	nMinY = m_rcVisual.bottom - (m_rcVisual.Height() >> 2) - rcPosition.Height();
	nMaxY = m_rcVisual.top + (m_rcVisual.Height() >> 2);
}

void CWEILayer::OnEndMove()
{
	CRect rcPosition;
	GetWindowRect(&rcPosition);
	
	if (E_ILAYER_TYPE_H == m_type)
	{
		int nWidth = rcPosition.Width();
		if (rcPosition.left > m_rcVisual.left)
		{
			while (rcPosition.left > m_rcVisual.left)
			{
				rcPosition.left -= 10;
				if (rcPosition.left < m_rcVisual.left)
				{
					rcPosition.left = m_rcVisual.left;
				}
				rcPosition.right = rcPosition.left + nWidth;
				MoveLayer(&rcPosition);
				OnLayerMoved();
				GetWindow()->UpdateWindow();
				Sleep(20);
			}

		}else if (rcPosition.right < m_rcVisual.right)
		{
			while (rcPosition.right < m_rcVisual.right)
			{
				rcPosition.right += 10;
				if (rcPosition.right > m_rcVisual.right)
				{
					rcPosition.right = m_rcVisual.right;
				}
				rcPosition.left = rcPosition.right - nWidth;
				MoveLayer(&rcPosition);
				OnLayerMoved();
				GetWindow()->UpdateWindow();
				Sleep(20);
			}
		}
		GetWindow()->IgnoreMsgBeforeTime();
	}else
	{
		int nHeight = rcPosition.Height();
		if (rcPosition.top > m_rcVisual.top)
		{
			while (rcPosition.top > m_rcVisual.top)
			{
				rcPosition.top -= 10;
				if (rcPosition.top < m_rcVisual.top)
				{
					rcPosition.top = m_rcVisual.top;
				}
				rcPosition.bottom = rcPosition.top + nHeight;
				MoveLayer(&rcPosition);
				OnLayerMoved();
				GetWindow()->UpdateWindow();
				Sleep(20);
			}

		}else if (rcPosition.bottom < m_rcVisual.bottom)
		{
			while (rcPosition.bottom < m_rcVisual.bottom)
			{
				rcPosition.bottom += 10;
				if (rcPosition.bottom > m_rcVisual.bottom)
				{
					rcPosition.bottom = m_rcVisual.bottom;
				}
				rcPosition.top = rcPosition.bottom - nHeight;
				MoveLayer(&rcPosition);
				OnLayerMoved();
				GetWindow()->UpdateWindow();
				Sleep(20);
			}
		}
		GetWindow()->IgnoreMsgBeforeTime();


	}
}

BOOL CWEILayer::CanSlide()
{
	CRect rcPosition;
	GetWindowRect(&rcPosition);

	if (E_ILAYER_TYPE_H == m_type)
	{
		if (rcPosition.left > m_rcVisual.left)
		{
			return FALSE;
		}

		if (rcPosition.right < m_rcVisual.right)
		{
			return FALSE;
		}


	}else
	{
		if (rcPosition.top > m_rcVisual.top)
		{
			return FALSE;
		}

		if (rcPosition.bottom < m_rcVisual.bottom)
		{
			return FALSE;
		}
	}

	return TRUE;
}

void CWEILayer::OnStyleDown(CWceUiLayer* pLayer)
{
	ASSERT(NULL != m_pDownLayer);
	if (m_pDownLayer->IsKindOf(WCEUI_CLASS_NAME(CWEIButton)))
	{
		CWEIButton* pBtn = (CWEIButton*)m_pDownLayer;
		LPCTSTR pDownStyle = pBtn->GetDownStyleName();
		LPCTSTR pNormolStyle = pBtn->GetNoramlStyleName();
		if (*pDownStyle)
		{
			pBtn->SetStyle(pDownStyle);
		}else
		{
			pBtn->SetStyle(pNormolStyle);
		}
	}
}

void CWEILayer::OnStyleEndDown(CWceUiLayer* pLayer)
{
	ASSERT(NULL != m_pDownLayer);
	if (m_pDownLayer->IsKindOf(WCEUI_CLASS_NAME(CWEIButton)))
	{
		CWEIButton* pBtn = (CWEIButton*)m_pDownLayer;
		LPCTSTR pNormolStyle = pBtn->GetNoramlStyleName();
		pBtn->SetStyle(pNormolStyle);
	}

	TRACE(L"%s is style end down\n", m_pDownLayer->GetName());
}


void CWEILayer::OnLayerMoved()
{
	GetCmdReceiver()->OnCommand(CMD_WE_I_MOVED, (WPARAM)this, 0);
}

void CWEILayer::SetSlideSpeed(int nFast, int nNormal, int nSlow)
{
	m_nFast		= nFast;
	m_nNormal	= nNormal;
	m_nSlow		= nSlow;
}

void CWEILayer::GetSlideSpeed(int& nFast, int& nNormal, int& nSlow) const
{
	nFast	 = m_nFast;
	nNormal  = m_nNormal;
	nSlow    = m_nSlow;
}


void CWEILayer::SetSlideFrequence(int nFreq)
{
	ASSERT(nFreq > 0);
	m_nFreq = nFreq;
}

void CWEILayer::SetBlockSlide(BOOL bBlockSlide)
{
	m_bBlockSlide = bBlockSlide;
}